package teste.timer;

import java.util.Timer;
import java.util.TimerTask;
import java.lang.Math;
import android.os.Handler;

/**
 * This Class implements a clock and/or a up/down counter
 * 
 * @author Filipe
 * @version 1.0
 * @since 15.09.2013
 */
public class relogio {
	
	// time convertion constants
	private static int secMs = 1000;
	private static int minMs = 60000;
	private static int hourMs = 3600000;
	
	private Timer timer;
	private TimerTask task;
	private Handler handler = new Handler();
    
    private long time;
	private long startTime;
	private int step;
	private int resolution = 0;
	private int up_down;
	private String format;
	private boolean paused = true;
	
	private String hours;
	private String minutes;
	private String seconds;
	private String milliseconds;
	
	/**
	 * This class constructor implements a clock and/or a up/down counter preparation
	 * 
	 * @param clockTime Start value for the clock/timer counter.
	 * @param resolutionType Sets the update period interval (timer resolution): 
	 *"horas",
	 *"minutos",
	 *"segundos",
	 *"milisegundos,
	 * @param updown Sets counter type: increment type "up", decrement type "down"
	 * @param clockFormat Chooses clock toString format: 
	 * hours "HH", minutes "MM", seconds "SS", miliseconds "mmm",
	 * the format shall be passed separated by ":", ex.: "HH:MM"
	 * @author Filipe
	 * @version 1.0
	 * @since 15.09.2013
	 */
	public relogio(long clockTime, String resolutionType, String updown,String clockFormat){
		
		startTime = clockTime;
		time = clockTime;
		format = clockFormat;
		if (updown == "Up"||updown == "up"){
			up_down = 1;
		}else if(updown == "Down"||updown == "down"){
			up_down = 0;
		}
		
		if (resolutionType=="milisegundos"){
//			secMs = 1000;		//em ms
//			minMs = 60000;		//em ms		
//			horMs = 3600000;	//em ms
			resolution = 0;
			step = 1;
		}else if (resolutionType=="segundos"){
//			secMs = 1;		//em segundos
//			minMs = 60;		//em segundos		
//			horMs = 3600;	//em segundos
			resolution = 1;
			step = secMs;
		}else if (resolutionType=="minutos"){
//			minMs = 1;			//em minutos		
//			horMs = 60;			//em minutos
			resolution = 2;
			step = minMs;
		}else{
//			horMs = 1;			//em horas
			resolution = 3;
			step = hourMs;
		}
	}
	
	/**
	 * This method sets a new start time for the clock timer
	 * 
	 * @param clockTime Start value for the clock/timer counter.
	 * @author Filipe
	 * @version 1.0
	 * @since 15.09.2013
	 */
	public void setClockTime(int clockTime){
		startTime = clockTime;
		time = startTime;
	}
	
	/**
	 * This method creates e new timer instance with a periodic interval "step".
	 */
	private void ativaTimer(){
    	timer = new Timer();
        task = new TimerTask() {
            public void run() {
                    handler.post(new Runnable() {
                            public void run() {
                                update();
                            }
                   });
            }};
            timer.schedule(task, step, step);
    }
	
	/**
	 * This method updates the timer counter by the "step" value.
	 */
	private void update(){
		if (up_down == 1){
			time+=step;
		}else if (up_down == 0){
			time-=step;
		}
	}
	
	/**
	 * This method sets the format of the toString method (String generation).
	 * 
	 * @param clockFormat Chooses clock toString format: 
	 * hours "HH", minutes "MM", seconds "SS", miliseconds "mmm",
	 * the format shall be passed separated by ":", e.g.: "HH:MM"
	 */
	public void setFormat (String clockFormat){
		format = clockFormat;
	}
	
	/**
	 * This method gets the actual format chosen.
	 * 
	 * @return toString formatter, e.g.: "HH:MM".
	 */
	public String getFormat (){
		return format;
	}
	
	/**
	 * This method sets the counter type.
	 *  
	 * @param updown Increment type "up", Decrement type "down".
	 */
	public void setUpDownMode(String updown){
		if (updown == "Up"||updown == "up"){
			up_down = 1;
		}else if(updown == "Down"||updown == "down"){
			up_down = 0;
		}
	}
	
	/**
	 * This method gets the counter type.
	 * 
	 * @return Increment type "up", Decrement type "down".
	 */
	public String getUpDownMode(){
		if (up_down==1){
			return "up";
		}else{
			return "down";
		}
	}
	
	/**
	 * Starts timer instance and task handler.
	 */
	public void start(){
		if (paused){
			paused = false;
			ativaTimer();
		}
	}
	
	/**
	 * Pauses or stops timer instance and task handler.
	 */
	public void pause(){
		if (!paused){
			paused = true;
			task.cancel();
			task = null;
			timer.cancel();
		}
	}
	
	/**
	 * Resumes timer counting, if it was stopped/paused.
	 */
	public void restart(){
		ativaTimer();
		start();
	}
	
	/**
	 * Resets timer counter to the configured start value.
	 */
	public void reset(){
		time = startTime;
	}
	
	/**
	 * Deletes and stops all timer threads or instances.
	 */
	public void delete(){
		pause();
		timer.purge();
	}
	
	/**
	 * This method gets the time actual counter value in milliseconds.
	 * @return
	 */
	public long getTime(){
		return time;		
	}
	
	/**
	 * This method gets the resolution type (step counter)
	 *  
	 * @return resolution type:
	 * "hours",
	 * "minutes",
	 * "seconds",
	 * "milliseconds".
	 */
	public String getResolutionType(){
		switch (resolution){
		
		case 0:
			return "milliseconds";
		case 1:
			return "seconds";
		case 2:
			return "minutes";
		case 3:
			return "hours";
		default:
			return null;
		
		}
	}
	
	/**
	 * This method gets the actual counter hours value.
	 * 
	 * @return Hours count value (long)
	 */
	public long getHours(){
		return time/hourMs;
	}
	
	/**
	 * This method sets a new hour value for counter.
	 * 
	 * @param num_hours Hour value to be applied (long)
	 */
	public void setHours(int num_hours){
		time %= hourMs;
		time += num_hours*hourMs;
	}
	
	/**
	 * This method gets the actual counter minutes value.
	 * 
	 * @return Minutes count value (long)
	 */
	public long getMinutes(){
		switch (resolution){
		case 3:
			return (Integer) null;
		default:
			return (time%hourMs)/minMs;
		}
	}
	
	/**
	 * This method sets a new minutes value for counter.
	 * 
	 * @param num_Minutes Minutes value to be applied (long)
	 */
	public void setMinutes(int num_Minutes){
		switch (resolution){
		case 3:
			return;
		default:
			time -= ((time%hourMs)/minMs)*minMs;
			time += num_Minutes*minMs;
		}
	}

	/**
	 * This method gets the actual counter seconds value.
	 * 
	 * @return Seconds count value (long)
	 */
	public long getSeconds(){
		switch (resolution){
		case 3:
			return (Integer) null;
		case 2:
			return (Integer) null;
		default:
			return (time%minMs)/secMs;
		}
	}
	
	/**
	 * This method sets a new seconds value for counter.
	 * 
	 * @param num_Seconds Seconds value to be applied (long)
	 */
	public void setSeconds(int num_Seconds){
		switch (resolution){
		case 3:
			return;
		case 2:
			return;
		default:
			time-=((time%minMs)/secMs)*secMs;
			time+= num_Seconds;
		}
	}
	
	/**
	 * This method gets the actual counter milliseconds value.
	 * 
	 * @return Milliseconds count value (long)
	 */
	public long getMilliseconds(){
		switch (resolution){
		case 0:
			return time%secMs;
		default:
			return (Integer) null;
		}
	}
	
	/**
	 * This method sets a new milliseconds value for counter.
	 * 
	 * @param num_Milisegundos Milliseconds value to be applied (long)
	 */
	public void setMilisegundos(int num_Milisegundos){
		switch (resolution){
		case 0:
			time-=(time%secMs);
			time+=num_Milisegundos;
		default:
			return;
		}
	}
	
	/**
	 * This method converts the hour value into a String
	 * 	
	 * @return (String) formatted "HH"
	 */
	public String toStringHours(){
		long abs_time;
		abs_time = Math.abs(time);
//		
//		if((abs_time/hourMs)<10){
//			return "0" + (abs_time/hourMs);
//		}else{
//			return "" + (abs_time/hourMs);
//		}
		return String.format("%02d", (abs_time/hourMs));
		
	}
	
	/**
	 * This method converts the minutes value into a String
	 * 	
	 * @return (String) formatted "MM"
	 */
	public String toStringMinutes(){
		long abs_time;
		abs_time = Math.abs(time);
		
//		if(resolution<3){
//			if((abs_time%horMs)/minMs<10){
//				return "0" + (abs_time%horMs)/minMs;
//			}else{
//				return "" + (abs_time%horMs)/minMs;
//			}
//		}else{
//			return null;
//		}
		return String.format("%02d",(abs_time%hourMs)/minMs);
	}
	
	/**
	 * This method converts the seconds value into a String
	 * 	
	 * @return (String) formatted "SS"
	 */
	public String toStringSeconds(){
		long abs_time;
		abs_time = Math.abs(time);
		
//		if(resolution<2){
//			if((abs_time%minMs)/secMs<10){
//				return "0" + (abs_time%minMs)/secMs;
//			}else{
//				return "" + (abs_time%minMs)/secMs;
//			}
//		}else{
//			return null;
//		}
		return String.format("%02d", (abs_time%minMs)/secMs);
	}
	
	/**
	 * This method converts the milliseconds value into a String
	 * 	
	 * @return (String) formatted "mmm"
	 */
	public String toStringMiliseconds(){
		long abs_time;
		abs_time = Math.abs(time);
		
//		if(resolution==0){
//			if((abs_time%secMs)<100){
//				if((abs_time%secMs)<10){
//					return "00" + (abs_time%secMs);
//				}else{
//					return "0" + (abs_time%secMs);
//				}
//			}else{
//				return "" + (abs_time%secMs);
//			}
//		}else{
//			return null;
//		}
		return String.format("%03d", (abs_time%secMs));
	}
	
	/**
	 * This method converts hour, minutes, seconds and milliseconds to a string formatted by clockFormat paramter
	 * 
	 * @return (String) time string formatted, e.g.: "HH:MM".
	 */
	@Override
	public String toString(){
		String final_text = null;
		
		hours = toStringHours();
		minutes = toStringMinutes();
		seconds = toStringSeconds();
		milliseconds = toStringMiliseconds();
		
		if (format.contains("HH:")){
			if (resolution==3){
				final_text = hours;
			}else{
				final_text = hours + ":";
			}
		}else if (format.contains("HH")){
			final_text = hours;
		}
		
		if (format.contains("MM:") && resolution<3){
			if (resolution==2){
				final_text += minutes;
			}else if (resolution<3){
				final_text += minutes + ":";
			}
		}else if (format.contains("MM")){
			final_text = minutes;
		}
		
		if (format.contains("SS:") && resolution<2){
			if (resolution==1){
				final_text += seconds;
			}else if (resolution<2){
				final_text += seconds + ":";
			}
		}else if (format.contains("SS")){
			final_text = seconds;
		}
		
		if (format.contains("mmm") && resolution<1){
			final_text += milliseconds;
		}

		if (time<0 && final_text != null){
			final_text = "-" + final_text;
		}
		
		//Log.d("Debug","final_text =" + final_text);
	
		return final_text;
		
	}
	
}
